import storyxml
import random
from random import *
import re

def parseMultiPath(node, parse):
	paths = parse.split("+")
	
	for segment in paths:
		path2 = segment.split("|")
		point = 0
		for path in path2:
			if path[0] == "!":
				#print "found a not", path
				success = parsePath(node, path[1:])
				if success == 0:
					#print "not succeeded!"
					point = 1
					break
				else:
					print "not failed!"
			else:
				#print "this is not a not", path
				success = parsePath(node, path)
				if success != 0:
					point = success
					break
		if point == 0:
			#print "returning 0"
			return 0
	#print "returning a success"
	return point

def parsePath(node, parse):
	print "Parsing path", parse
	path = parse.split(':')
	point = node
	
	#print "---Parsing:", parse
	
	for step in path:
		#print step, point._name
		#if point._name == "location":
			#print point.id
		if len(step) > 0:
			if step == "$location":
				done = False
				while done == False:
					if point._parent is None:
						#the base node counts as a location!
						done = True
						break
					point = point._parent
					if point._name == "location":
						done = True
						
				print point.id, "found from $location"
			elif step == "$parent":
				point = point._parent
			elif step == "$root":
				while point._parent is not None:
					point = point._parent
			elif step[0] == '@': #find location child operator
				id = step[1:]
				ok = 0
				for child in point._children:
					if hasattr(child, "id") == True:
						if child.id == id:
							point = child
							ok = 1
							break
				if ok == 0:
					print step, " @ failed"
					return 0
			else:
				#print "step", step
				ok = 0
				for child in point._children:
					#print "child", child._name
					if child._name == step:
						ok = 1
						point = child
						break
				if ok == 0:
					print step + " child failed"
					return 0
	return point

def parseFullPath(node, parse):
	sp = parse.split('.')
	
	if sp[0] != '':
		point = parseMultiPath(node, sp[0])
		if point == 0:
			print sp[0] + " path failed"
			return 0
	else:
		point = node
	
	if len(sp) > 1:
		if hasattr(point, sp[1]) is False:
			print sp[1] + " var failed"
			return 0
			
		return getattr(point, sp[1])
			
	return point
		
def parseText(node, text):
	text = text.lstrip().rstrip()
	l = text.split(' ')
	for i in range(0, len(l)):
		if l[i] == '':
			continue
		if l[i][0] == "#":
			word = l[i].split("#", 2)
			val = parseFullPath(node, word[1])
			if val == 0:
				val = "ERROR!"
			path = word[1].split('.')[0]
			val = parseText(parsePath(node, path), val)
			
			if len(word) > 2:
				val += word[2]
			l[i] = val
			
		if l[i][0] == "@":
			word = l[i].split("@", 2)
			val = parseFullPath(node, word[1])
			if val == 0:
				val = "ERROR!"
			path = word[1].split('.')[0]
			val = parseText(parsePath(node, path), val)
			
			if len(word) > 2:
				val += word[2]
			l[i] = val[0].capitalize() + val[1:]
			
	return ' '.join(l)

class CrumbParser:
	def __init__(self):
		self.funcs = {}
		self.registerFunc("random", self.doRandom)
		self.registerFunc("print", self.doPrint)
		self.registerFunc("trail", self.doTrail)
		self.registerFunc("prereq", self.doPrereq)
		self.registerFunc("set", self.doSet)
		self.registerFunc("do", self.doDo)
		self.registerFunc("staticdo", self.doStaticDo)
		self.registerFunc("location", self.doLocation)
		self.registerFunc("spill", self.doSpill)
		self.registerFunc("staticrandom", self.doStaticRandom)
		self.registerFunc("staticprereq", self.doStaticPrereq)
		self.registerFunc("debug", self.doDebug)
		self.registerFunc("if", self.doIf)
		self.registerFunc("staticif", self.doStaticIf)
		self.registerFunc("remove", self.doRemove)
		
	def registerFunc(self, name, func):
		self.funcs[name] = func
	
	def printFuncs(self):
		for item in self.funcs:
			print item
		
	def doRandom(self, node):
		#print "random!"
		#print node._parent._parent
		#default n
		if hasattr(node, "n") is False:
			node.n = 1
		else:
			node.n = int(node.n)
			
		if hasattr(node, "r") is True:
			node.r = int(node.r)
			node.n = randint(node.n, node.n + node.r)
			
		#parse any neccesary nodes
		if hasattr(node, "parse"):
			regex = re.compile(node.parse)
			
			i = 0
			
			while(i < len(node._children)):
				child = node._children[i]
				#print i, child
				if regex.match(child._name) is not None:
					#print "regex matched"
					result = self.parseCrumb(child)
					if result[0] == 0:
						node._children.pop(i)
						i -= 1				#Because it is incremented later, but we don't want it to be. Simplest solution.
						
					for child in result[1]:
						node._children.insert(i, child)
						
					#this should not support jumping! Don't do it!
						
				i += 1
				
		
		#select n nodes
		selected = []
		while(node.n > 0):
			if len(node._children) == 0:
				return (0, selected)
			sel = randint(0, len(node._children) - 1)
			#print sel
			selected.append(node._children[sel])
			del node._children[sel]
			node.n -= 1
			
		#print "ending random"
		#print node._parent._parent
			
		return (0, selected)
	
	def doStaticRandom(self, node):
		#print node._parent._parent
		#default n
		if hasattr(node, "n") is False:
			node.n = 1
		else:
			node.n = int(node.n)
			
		if hasattr(node, "r") is True:
			node.r = int(node.r)
			node.n = randint(node.n, node.n + node.r)
			
		#parse any neccesary nodes
		if hasattr(node, "parse"):
			regex = re.compile(node.parse)
			
			i = 0
			
			while(i < len(node._children)):
				child = node._children[i]
				#print i, child
				if regex.match(child._name) is not None:
					#print "regex matched"
					result = self.parseCrumb(child)
					if result[0] == 0:
						node._children.pop(i)
						i -= 1				#Because it is incremented later, but we don't want it to be. Simplest solution.
						
					for child in result[1]:
						node._children.insert(i, child)
						
					#this should not support jumping! Don't do it!
						
				i += 1
				
		
		#select n nodes
		selected = []
		selrange = range(len(node._children))
		n = node.n
		while(n > 0):
			if selrange == 0:
				return (1, [])
			sel = randint(0, len(selrange) - 1)
			#print sel
			selected.append(selrange[sel])
			del selrange[sel]
			n -= 1
			
		#execute selected nodes
		for num in selected:
			self.parseCrumb(node._children[num])
			
		return (1, [])
			
	def doPrint(self, node):
		print parseText(node, node.text)
		return (1, [])
	
	def doDebug(self, node):
		if hasattr(node, "parse"):
			point = parseFullPath(node, node.parse)
			if point == 0:
				print "debug " +node.parse +" failed, no full path"
				return (1, [])
			print point
		else:
			print node._parent
		return (1, [])
		
	def doPrereq(self, node):
		point = parseFullPath(node, node.parse)
		if point == 0:
			#print "prereq " +node.parse +" failed, no full path"
			return (0, [])
		elif type(point) != type(node) and point != 1: #if it is a var, additional checking is needed.
			if hasattr(node, "regex") is True:
				regex = re.compile(node.regex)
				if regex.match(point) is None:
					#print node.parse, node.regex, " failed"
					return (0, [])
			else:
				print "Warning: prereq missing regex/value"
				return (0, [])
		
		#print node.parse , "prereq success"
		node._children.reverse()
		return (0, node._children)
	
	def doIf(self, node):
		success = False
		point = parseFullPath(node, node.parse)
		if point == 0:
			print "if " +node.parse +" failed, no full path"
		elif type(point) != type(node) and point != 1: #if it is a var, additional checking is needed.
			if hasattr(node, "regex") is True:
				regex = re.compile(node.regex)
				if regex.match(point) is not None:
					success = True
			else:
				print "Warning: if missing regex/value, aborted everything."
				return (0, [])
		else:
			success = True
		
		#print node.parse , "prereq success"
		
		point = node._children[1]
		if success == True:
			point = node._children[0]
		
		point._children.reverse()
		return (0, point._children)
	
	def doStaticIf(self, node):
		success = False
		point = parseFullPath(node, node.parse)
		if point == 0:
			print "if " +node.parse +" failed, no full path"
		elif type(point) != type(node) and point != 1: #if it is a var, additional checking is needed.
			if hasattr(node, "regex") is True:
				regex = re.compile(node.regex)
				if regex.match(point) is not None:
					success = True
			else:
				print "Warning: if missing regex/value, aborted everything."
				return (0, [])
		else:
			success = True
		
		#print node.parse , "prereq success"
		
		point = node._children[1]
		if success == True:
			point = node._children[0]
		
		ret = 1
		parse = point._children
		for child in parse:
			end = self.parseCrumb(child)
			if end[0] > 1:
				ret= 3
				break
		return (ret, [])
	
	def doStaticPrereq(self, node):
		point = parseFullPath(node, node.parse)
		if point == 0:
			#print "prereq " +node.parse +" failed, no full path"
			return (1, [])
		elif type(point) != type(node) and point != 1: #if it is a var, additional checking is needed.
			if hasattr(node, "regex") is True:
				regex = re.compile(node.regex)
				if regex.match(point) is None:
					#print node.parse, node.regex, " failed"
					return (1, [])
			else:
				print "Warning: prereq missing regex/value"
				return (1, [])
		
		#print node.parse , "prereq success"
		ret = 1
		parse = node._children
		for child in parse:
			end = self.parseCrumb(child)
			if end[0] > 1:
				ret= 3
				break
		return (ret, [])	

	def doTrail(self, node):
		#get the other file
		trail = storyxml.getXML(node.file)
		xml = storyxml.parseXML(trail.documentElement)[0]
		xml._parent = node
		node._children.append(xml)
		#parse it and add it to the childs
		result = self.parseCrumb(xml)
		
		if result[0] == 0:
			node._children.remove(xml)

		for child in result[1]:
			node._children.append(child)
			
		return (0, node._children)

	def doSet(self, node):
		#set a variable on something
		sp = node.parse.split(".")
		point = parsePath(node, sp[0])
		if point != 0:
			setattr(point, sp[1], node.value)
			print "Set:", point._name, node.value
			if point._name == "location":
				print point.id
		else:
			#print node._parent._parent._parent._parent._parent
			print "Set " + sp[0] + "." + sp[1] + " not found."
			
		
		return (1, [])
		
	def doDo(self, node): #LAWL DOODOO
		node._children.reverse()
		return (0, node._children)
	
	def doStaticDo(self, node):
		i = len(node._children) - 1
		while(i >= 0):
			result = self.parseCrumb(node._children[i])
			if result[0] == 0 or result[0] == 2:
				node._children.pop(i)
			else:
				i -= 1
				
			for child in result[1]:
				node._children.insert(i, child)
				i += 1
				
			if result[0] > 1:
					break
				
		return (1, [])
		
	def doLocation(self, node):
		#print "Found Location", node.id, "in", node._parent
		if hasattr(node, "locations") == False:
			point = node._parent
			if node._parent._name != "location":
				point = parsePath(node, "$location")
				if point == 0:
					point = node._parent
			print "Location", node.id, "added to", point.id
			
			if hasattr(point, "locations") == False:
				point.locations = []
			point.locations.append(node)
			node._parent = point
			node.locations = []
			
			if len(node._children) > 0:
				first = node._children[0]
				if first._name == "preparse":
					first._children.reverse()
					x = 0 #keep track of how many children are part of the preparse
					for item in first._children:
						node._children.insert(1, item)
						x += 1
						
					node._children.pop(0)
						
					i = 0
					while(i < x):
						#print i, x, len(node._children)
						result = self.parseCrumb(node._children[i])
						if result[0] == 0:
							node._children.pop(i)
							x -= 1 #we removed a node.
						else:
							i += 1
							
						for child in result[1]:
							node._children.insert(i, child)
							x += 1 #this child is part of the preparse
						
						#preparse should not cause jumps.
					
				#print node
	
			#don't parse it right now. Wait for the external program to parse.
		
		return (1, [])
	
	def doSpill(self, node):
		point = parsePath(node._parent, node.parse)
		if point == 0:
			print "Spill path not found:", node.parse
			return (0, [])
		print "Spilled", node.parse, "into", point._name
		
		for child in node._children:
			point._children.append(child)
			child._parent = point
		return (0, [])
	
	def doRemove(self, node):
		point = parsePath(node._parent, node.parse)
		if point == 0:
			print "Remove not found:", node.parse, "Maybe you're psycic?"
			return (0, [])
		
		for i in range(0, len(point._parent._children)):
			if point._parent._children[i] == point:
				print "Removed", node.parse, point._parent._children[i]._name
				point._parent._children.pop(i)
				break
			
		print point._name, point._parent._name, "<------"
		for item in point._parent._children:
			print item._name
			
		print "Finished removing."
			
		return (0, [])
		
	#valid function return codes:
	#0: Remove this node, continue parsing.
	#1: Keep this node, continue parsing.
	#2: Remove this node, stop parsing.
	#3: Keep this node, stop parsing.
	def parseCrumb(self, node, force=False):
		#print "PARSING:" , node
		if node._name in self.funcs and force is False:
			return self.funcs[node._name](node)
		else:
			i = 0
			ret = 1
			while(i < len(node._children)):
				result = self.parseCrumb(node._children[i])
				if result[0] == 0 or result[0] == 2:
					node._children.pop(i)
				else:
					i += 1
					
				for child in result[1]:
					node._children.insert(i, child)
					
				if result[0] > 1:
					ret = 3
					break
				
			#print i, len(node._children)
				
			return (ret, [])
